﻿using System;
using System.Collections.Generic;
using System.Windows.Input;
using GameEngine.Model;
using GameEngine.Model.Data;
using GameEngine.View.Components;
using PureMVC.Interfaces;
using PureMVC.Patterns;

namespace GameEngine.View
{
    public class ThingMediator<MyIdType, MyBaseUIElementType> : Mediator, IThingMediator<MyIdType, MyBaseUIElementType>
        where MyIdType : IComparable<MyIdType>
    {
        public readonly IWorldDataProxy<MyIdType> World;
        protected IDictionary<IThingVOId<MyIdType>, IThingView<MyIdType, MyBaseUIElementType>> Items = new Dictionary<IThingVOId<MyIdType>, IThingView<MyIdType, MyBaseUIElementType>>();
        public event Action<IThingDataProxy<MyIdType>> OnHeightChange;
        public event Action<IThingDataProxy<MyIdType>> OnPositionChange;
        //public event Action<IThingDataProxy<ItemVOId>> OnDirectionChange;

        public ThingMediator(IWorldDataProxy<MyIdType> world)
            : base(IThingMediatorConstants<MyIdType>.GetMediatorNameFromProxy(world), null)
        {
            World = world;
        }

        #region IMediator Members

        /// <summary>
        /// List the <c>INotification</c> names this <c>Mediator</c> is interested in being notified of
        /// </summary>
        /// <returns>The list of <c>INotification</c> names </returns>
        override public IList<string> ListNotificationInterests()
        {
            return new List<string>() {
                World.THINGADDED_NOTIFICATION,
                World.THINGREMOVED_NOTIFICATION,
                IThingDataProxyConstants<MyIdType>.THINGCHANGED_NOTIFICATION,
                IThingTypeDataProxyConstants<MyIdType>.THINGTYPECHANGED_NOTIFICATION,
                IViewDataProxyConstants<MyIdType>.THINGTYPECVIEWHANGED_NOTIFICATION,
            };
        }

        /// <summary>
        /// Handle <c>INotification</c>s
        /// </summary>
        /// <param name="notification">The <c>INotification</c> instance to handle</param>
        /// <remarks>
        ///     <para>
        ///        Typically this will be handled in a switch statement, with one 'case' entry per <c>INotification</c> the <c>Mediator</c> is interested in. 
        ///     </para>
        /// </remarks>
        override public void HandleNotification(INotification notification)
        {
            switch(notification.Name){
                case IThingDataProxyConstants<MyIdType>.THINGCHANGED_NOTIFICATION:
                    {
                        IThingDataProxy<MyIdType> thingProxy = notification.Body as IThingDataProxy<MyIdType>;
                        if (Items.ContainsKey(thingProxy.Id))
                        {
                            switch (notification.Type)
                            {
                                //case IThingDataProxyConstants.THINGCHANGEDDIRECTION_NOTIFICATIONTYPE:
                                //    if (OnDirectionChange != null)
                                //        OnDirectionChange(thingProxy);
                                //    //GetThingDataProxyView(thingProxy).UpdateState(thingProxy.ViewState);
                                //    break;
                                case IThingDataProxyConstants<MyIdType>.THINGCHANGEDPOSITION_NOTIFICATIONTYPE:
                                    if (OnPositionChange != null)
                                        OnPositionChange(thingProxy);
                                    break;
                                case IThingDataProxyConstants<MyIdType>.THINGCHANGEDHEIGHT_NOTIFICATIONTYPE:
                                    if (OnHeightChange != null)
                                        OnHeightChange(thingProxy);
                                    break;
                                case IThingDataProxyConstants<MyIdType>.THINGCHANGEDSTATE_NOTIFICATIONTYPE:
                                    Items[thingProxy.Id].UpdateState(thingProxy.State);
                                    break;
                            }
                        }
                    }
                    break;
                case IThingTypeDataProxyConstants<MyIdType>.THINGTYPECHANGED_NOTIFICATION:
                    {
                        /*IThingTypeDataProxy<ItemVOId> thingTypeProxy = notification.Body as IThingTypeDataProxy<ItemVOId>;
                        foreach (IThingVOId<ItemVOId> thingId in items.Keys)
                        {
                            if (World.Items[thingId].TypeId == thingTypeProxy.Id)
                            {
                                items[thingId].UpdateState();
                            }
                        }*/
                    }
                    break;
                case IViewDataProxyConstants<MyIdType>.THINGTYPECVIEWHANGED_NOTIFICATION:
                    {
                        /*IViewDataProxy<ItemVOId> viewProxy = notification.Body as IViewDataProxy<ItemVOId>;
                        foreach(IThingTypeVO<ItemVOId> thingTypeProxy in ModelFacade<ItemVOId>.Instance.Engine.Game.ThingTypes.Values){
                            if(thingTypeProxy.ViewId == viewProxy.Id){
                                foreach(IThingVOId<ItemVOId> thingId in items.Keys){
                                        if(World.Items[thingId].TypeId==thingTypeProxy.Id){
                                            items[thingId].Update();
                                        }
                                }
                            }
                        }*/
                    }
                    break;
            }
        }

        /// <summary>
        /// Called by the View when the Mediator is registered
        /// </summary>
        override public void OnRegister()
        {
        }

        /// <summary>
        /// Called by the View when the Mediator is removed
        /// </summary>
        override public void OnRemove()
        {
            //RemoveThing
        }

        #endregion

        virtual public IThingView<MyIdType, MyBaseUIElementType> GetThingDataProxyView(IThingDataProxy<MyIdType> thing)
        {
            if(Items.ContainsKey(thing.Id))
                return Items[thing.Id];
            else
                return null;
        }

        virtual public IThingDataProxy<MyIdType> GetProxyFromView(IThingView<MyIdType, MyBaseUIElementType> view)
        {
            foreach(var keyPair in Items)
                if(keyPair.Value.Equals(view))//TODO id
                    return ModelFacade<MyIdType>.Helper.GetThingDataProxy(keyPair.Key);
            return null;
        }

        virtual public void AddThing(IThingDataProxy<MyIdType> proxy, IThingView<MyIdType, MyBaseUIElementType> view)
        {
            //MyThingView view = ViewFacade<MyWorldView, MyMapView, MyThingView, MyIdType, MyBaseUIElementType>.Instance.CreateViewInstance();
            Items.Add(proxy.Id,view);
            view.Tooltip = proxy.Id.Name;
            view.MouseLeftButtonUp += new MouseButtonEventHandler(view_MouseLeftButtonUp);
            view.MouseLeftButtonDown += new MouseButtonEventHandler(view_MouseLeftButtonDown);
            IViewVO<MyIdType> viewVO = ModelFacade<MyIdType>.Instance.Game.Views[
                    ModelFacade<MyIdType>.Instance.Game.ThingTypes[proxy.VO.TypeId].ViewId
                    ];
            view.Initialize(viewVO);
            //view.MouseLeftButtonDown += new ItemMouseButtonEventDelegate<ItemView>(ViewComponent_ItemMouseLeftButtonUp);
       }

        void view_MouseLeftButtonUp(object o, MouseButtonEventArgs e)
        {
            SendNotification(IThingMediatorConstants<MyIdType>.ITEMMOUSEUP, GetProxyFromView(o as IThingView<MyIdType, MyBaseUIElementType>));
        }

        void view_MouseLeftButtonDown(object o, MouseButtonEventArgs e)
        {
            SendNotification(IThingMediatorConstants<MyIdType>.ITEMMOUSEDOWN, GetProxyFromView(o as IThingView<MyIdType, MyBaseUIElementType>));
        }

        virtual public void RemoveThing(IThingVOId<MyIdType> thing)
        {
            Items.Remove(thing);
        }

    }
}